在與諸位CAE老司機正式發車前,我們先來看看如何在VSCode
內編寫ANSA,了解何謂deck
及速覽一些之後會用的Python小技巧。
透過ANSA上方menu,依序按下Tools –> Script –> Script Editor
,可開啟內建的編輯器,Script Editor
。
Script Editor
的功能比較陽春,我們一般只做為執行介面或Debug時使用。實際coding,我們會在VSCode
內來做。
在v22.1.0
前,如果想要自動提示來顯示相關函數及參數名的話,需要聯絡原廠或經銷商取得相關package
後,自行安裝。
但在v23.0.0
之後,已經可以利用ANSA介面安裝獨立的VSCode
及其相關提示package
。由於ANSA function
的名字有時候相當長,對於不是天天使用的function
,往往都得回去翻說明文件,現在有了自動提示function
及parameter
,實在方便許多。
如何安裝可以參考說明文件內的BCS Development Environment with Microsoft Visual Studio Code
。我們選擇最直觀的Download from Microsoft
安裝,但安裝過程會出現:
:: Setting build path /tmp
:::: Downloading bcs-dev-env extension
<urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1108)>
>> Invalid bcs_dev_env_vsix
經過一番研究後,發現這個安裝是透過一個Python script。於是我們決定修改~/BETA_CAE_Systems/ansa_v23.0.0/scripts/BuildBcsDevEnv/DevEnvBuilder.py
,添加下面兩行程式碼:
import ssl
ssl._create_default_https_context = ssl._create_unverified_context
如此,即可順利安裝,以後我們就可以通過Tools > Script > Visual Studio Code
來開啟一個有ANSA API自動提示的VSCode
開發環境了。
請注意:
Ubuntu 20.04.4 LTS
,您的作業系統或安裝路徑未必與我們相同,所以可能需要自己摸索一下該檔案的確切位置。ANSA是多種solver的前處理環境,針對某些操作時,需要明確說明當前指令是針對哪一種solver,所以常常需要給定一個deck
參數。由於我們是以LS-DYNA為例,所以我們的deck
會固定為constants.LSDYNA
。
from ansa import constants
deck = constants.LSDYNA
觀察deck
,可以發現其值是一個int
的2
,原來ANSA是用不同整數值來代表不同的solver。
def func(deck=None):
deck = deck or constants.LSDYNA
如果我們在呼叫func
時,不給定deck
,那麼deck
就會是預設的None
。由於bool(None)
會是False
,所以or
會short circuit地選擇constants.LSDYNA
做為deck
的值。
假設func
會回傳一個iterable
,我們可以用unpack的技巧來取得iterable
的任意元素。
如果要取得第一個元素a
,可以這麼寫:
a, *_ = func()
如果要取得第二個元素a
,可以這麼寫:
_, a, *_ = func()
如果要取得最後一個元素a
,可以這麼寫:
*_, a = func()
假如我們想對一個iterable
中的元素做一些運算,或是過濾掉一些不要的元素,最後再用一個container
收集想要的結果,常用的作法如下:
numbers = []
for i in range(10):
if i % 2:
numbers.append(i)
但如果使用list comprehensionts
可以使code更簡潔,執行速度也會更快。
我們習慣將list comprehensionts
拆成三行,第一行是最後經過運算需要放進container
的結果,第二行是迴圈,第三行是過濾的條件。
numbers = [i
for i in range(10)
if i % 2]
這兩個方法都可以得到相同的結果。
numbers=[1, 3, 5, 7, 9]
generator expressions
跟list comprehensions
非常像,只需要將[]
改為()
即可。但list comprehensions
會真的產生list
,generator expression
只會產生一個generator
。
有時候我們只想要取一個iterable
中的幾個值,如最大最小等,generator
會是一個不錯的選擇。
例如下面的程式碼,我們不需要知道產生的每一個值,而只想知道那些值裡的最小值。
from random import randint
min_ = min(randint(1, 100)
for _ in range(10))
sorted
可以將給定的iterable
,依照key
來進行排列後,回傳一個list
。
例如下面的程式碼,我們產生一個list
,裡面包含十組tuple
,tuple
的第一個element代表產生的順序,而第二個element為一個介於1~10
的隨機整數。
透過key
這個參數,我們可以傳入itemgetter(1, 0)
,意思是這10
組tuple
比較的邏輯為先比第二個element,如果一樣再比第一個element(Python的index
由0
開始)。
from operator import itemgetter
from random import randint
numbers = [(i, randint(1, 10))
for i in range(1, 11)]
print(sorted(numbers, key=itemgetter(1, 0)))
其輸出結果為:
[(2, 1), (10, 1), (4, 4), (6, 5), (5, 6), (8, 6), (1, 9), (3, 9), (7, 10), (9, 10)]
利用class
來實現context manager
需要實作__enter__
及__exit__
兩個function
。
context manager
讓我們可以使用with
來達到進入及離開某段程式碼時,自動執行__enter__
及__exit__
。
實務上要實作context manager
的機會並不高,我們會在本系列文中後段,學習如何快速產生node
及shell
等Entity
時,實作這個功能。
一個簡單的context manager
架構大致如下。
class CtxMgr:
def __init__(self, a):
'''
Do some init if needed
'''
self.a = a
def hello(self):
print('Hello !')
def __enter__(self):
print('__enter__ called')
return self
def __exit__(self, exc_type, exc_value, exc_tb):
print('__exit__ called')
del self.a
def main():
with CtxMgr('a') as ctxmgr:
ctxmgr.hello()
print(f'{ctxmgr.a=}') # get 'a' back
# will raise AttributeError if called outside with
print(ctxmgr.a)
if __name__ == '__main__':
main()
我們可以看出一使用with
,會先呼叫__enter__ function
,接著會是我們自己呼叫的hello function
,最後要離開with
前,則會呼叫__exit__ function
。當在with
的範圍內,我們可以取得self.a
,但當離開with
後,若想再取得self.a
,則會產生AttributeError
,原因是因為self.a
已經在離開with
前,被__exit__
刪除了。
其輸出結果為:
__enter__ called
Hello !
ctxmgr.a='a'
__exit__ called
AttributeError: 'CtxMgr' object has no attribute 'a'
想快速了解ANSA API的話,可以參考軟體說明文件內Getting Started
的10 Minutes to ANSA API
。